﻿using Jacobi.Vst.Core;
using Jacobi.Vst.Framework;
using Microsoft.VisualBasic;
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Windows.Threading;
using System.Xml;
using Aleator.Core;
using Aleator.Helpers;
using Aleator.Resources;
using System.Threading.Tasks;
using Sanford.Multimedia.Midi;

namespace Aleator.Core
{
	/// <summary>
	/// Session object generates MIDI data, organizes it and sends events to the VST host in syncronicity with the internal clock
	/// </summary>
	public class Session : INotifyPropertyChanged
	{
		#region Members
		private static PhraseFactory m_phraseFactory = new ConcretePhraseFactory();

		private Thread m_workerThread;
		private Aleator.Core.KeySignatureBuilder m_KeySignatureBuilder;

		private static NoteFactory m_notefactory = new ConcreteNoteFactory();

		private int m_iteration;
		private int m_keyNumber;

		private List<ConcreteNote> m_noteOnList;
		private List<ConcreteNote> m_noteOffList;

		private string m_suite;
		private bool m_isManual;

		private int m_selectedKeyValue;

		private int m_currentBeat;

		private int m_majorTicks;
		private int m_majorTicksPhrase;

		private int PPQN = Convert.ToInt16(AppResources.PulsesPerQuarterNoteString);

		public List<int> m_tempoList;
		private List<Track> m_tracks = new List<Track>();

		private int m_bpm;

		private int m_progressionCtr;

		private int m_oldProgressionID;

		private string m_oldChord;

		private int m_tempo;

		private bool m_metronome;
		private bool m_crash;

		private bool m_isPlaying;
		private bool m_drumsMuted;
		private bool m_bassMuted;
		private bool m_rhythmMuted;
		private bool m_melodyMuted;
		private bool m_arpMuted;
		private bool m_utilityMuted;

		private static bool m_paused;
		private static bool m_pending;

		private bool m_currentNoteIsPlaying;

		private ConcreteNote m_currentDisplayNote;

		private static MidiProcessor m_processor;
		private VstEventCollection m_events;
		private VstEventCollection m_eventsTmp;

		private TempoChangeBuilder m_tempoChanger;

		private List<Composition> m_alreadyPlayed;
		private List<CompositionLite> m_compositions;

		private Dictionary<int, string> m_keyBindingList;

		private List<ConcreteNote> m_notes;

		private CompositionLite m_selectedComposition;
		private Composition m_currentComposition;

		private XmlDocument m_document;
		private XmlNode m_root;
		private XmlNodeList m_compositionList;

		private byte[] m_compositionIDs;

		private Microsoft.VisualBasic.Devices.ComputerInfo m_computerInfo;
		private DateTime m_startTime;
		private static DateTime m_stopTime;

		private ConcretePhrase m_pendingPhrase;
		private PhraseFactory.PhraseType m_pendingPhraseType;

		private object m_lock;

		#endregion

		#region Constructors

		/// <summary>
		/// Generic constructor
		/// </summary>
		public Session(IVstMidiProcessor midiProcessor, bool metronome)
		{
			Metronome = metronome;

			m_computerInfo = new Microsoft.VisualBasic.Devices.ComputerInfo();
			m_startTime = DateTime.MinValue;

			m_processor = (MidiProcessor)midiProcessor;
			m_events = new VstEventCollection();
			m_eventsTmp = new VstEventCollection();

			m_tempoList = new List<int>();

			int min = Int32.Parse(AppResources.MinTempo) * 10;
			int max = (Int32.Parse(AppResources.MaxTempo) * 10) + 1;

			for (int i = min; i < max; i++)
				m_tempoList.Add(i);

			//Tempo = 120;

			m_document = new XmlDocument();

			m_document.Load(Aleator.Resources.AppResources.CompositionDocumentPath);
			m_root = m_document.SelectSingleNode("/Compositions");
			m_compositionList = m_root.SelectNodes("Composition");
			m_compositionIDs = new byte[m_compositionList.Count];

			m_compositions = new List<CompositionLite>();
			m_alreadyPlayed = new List<Composition>();

			XmlNode c_node = null;

			for (int i = 0; i <= m_compositionList.Count; i++)
			{
				if (i < m_compositionList.Count)
					m_compositionIDs[i] = (byte)(i + 1);

				if (i == 0)
					m_compositions.Add(new CompositionLite(i, "Random selection", string.Empty));
				else
				{
					c_node = m_compositionList.Item(i - 1);
					m_compositions.Add(new CompositionLite(i, c_node.Attributes.GetNamedItem("Name").InnerText, c_node.Attributes.GetNamedItem("Mode").InnerText));
				}
			}

			if (SelectedComposition == null || SelectedComposition.CompositionID == 0)
				SelectedComposition = m_compositions[0];

			Suite = m_root.Attributes.GetNamedItem("Suite").InnerText;

			//Default MIDI note boundaries
			LowNote = 0;
			HighNote = 127;

			Clock = new MidiInternalClock();
			Clock.Ppqn = PPQN;

			m_tempoChanger = new TempoChangeBuilder();

			//Tempo = (int)m_processor.Tempo;

			//Stay within 3 octaves for now (HomeOctave - 1 to HomeOctave  1) for the whole session for now
			OctaveVariance = 1;

			DrumPhrase.LoadRhythms();

			LoadComposition(HighNote, LowNote);

			//m_workerThread = new Thread(() =>
			//{
			//    //LoadComposition(HighNote, LowNote);
			//    //TODO: Move this logic to the UI thread

			//    PrepareUIProperties();

			//    if (PropertyChanged != null)
			//    {
			//        SmartDispatcher.BeginInvoke(delegate
			//        {
			//            Loaded(this, null);
			//        });
			//    }
			//});

			//m_workerThread.IsBackground = true;
			//m_workerThread.Start();

			Logger.Log(TraceEventType.Information, "Session instantiated.");
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="highNote">Highest note that can be played during this session</param>
		/// <param name="lowNote">Lowest note that can be played durign this session</param>
		public Session(int highNote, int lowNote)
		{
			RndGenerator = new Random();
			Clock = new MidiInternalClock();

			//Set tempo equal to host tempo
			SetTempo();

			LoadComposition(highNote, lowNote);
		}

		#endregion

		#region Event Handlers
		/// <summary>
		/// Handler for the clock tick event. With the clock resolution (PPQN) set to 96, that means 48 ticks is the duration of an 8th and
		/// and 24 ticks is the duration of a 16th note. PPQN must be set higher for anything more granular than 32nd notes.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Clock_Tick(object sender, EventArgs e)
		{
			if (CurrentComposition != null && (Clock.Ticks == 0 || Clock.Ticks % TickNumber == 0))
			{
				//Grab all of the notes for the current beat, measure, progression and composition counters
				if (m_computerInfo.AvailablePhysicalMemory < 4000000000)
				{
					Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();

					Logger.Log(TraceEventType.Error, "Reaper memory leak detected. Aleator memory allocation: " + currentProcess.WorkingSet64);
					throw new OutOfMemoryException("Reaper memory leak detected. Aleator memory allocation: " + currentProcess.WorkingSet64);
				}

				GetEvents();

				//Iterate through all of the counters
				ProcessTicks();

				//Update UI with new measure and beat values
				NotifyUI();

				//Process and clear all MIDI events
				m_processor.Process(m_events);

				m_events.Clear();
			}
		}
		#endregion

		#region Events

		/// <summary>
		/// Event handler for the UI load
		/// </summary>
		public EventHandler Loaded;

		#endregion

		#region Properties

		[Bindable(true)]
		public List<CompositionLite> Compositions
		{
			get
			{
				return m_compositions.ToList();
			}
			set
			{
			}
		}

		/// <summary>
		/// Convenience property for suite
		/// </summary>
		public const string SuitePropertyName = "Suite";

		/// <summary>
		/// Name of the current suite
		/// </summary>
		[Bindable(true)]
		public string Suite
		{
			get
			{
				return m_suite;
			}
			set
			{
				m_suite = value;
			}
		}

		/// <summary>
		/// Title of the current movement
		/// </summary>
		public string Movement
		{
			get
			{
				return CurrentComposition.Name;
			}
		}

		/// <summary>
		/// Boolean indicating whether the phrases are being controlled manually
		/// </summary>
		public bool IsManual
		{
			get
			{
				return m_isManual;
			}
			set
			{
				m_isManual = value;
			}
		}

		/// <summary>
		/// Random number generator to be used for throughout session
		/// </summary>
		static public Random RndGenerator = new Random();

		/// <summary>
		/// MIDI clock to generate clicks
		/// </summary>
		static public MidiInternalClock Clock;

		/// <summary>
		/// Convenience property for CurrentBeat
		/// </summary>
		public const string CurrentBeatPropertyName = "CurrentBeat";

		/// <summary>
		/// Display beat + 1 to the user
		/// </summary>
		[Bindable(true)]
		public int CurrentBeat
		{
			get
			{
				return m_currentBeat + 1;
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Current measure of the session
		/// </summary>
		public int CurrentMeasure
		{
			get
			{
				return CurrentComposition.CurrentProgression.CurrentMeasure;
			}
		}

		/// <summary>
		/// Convenience property for CurrentMeasure
		/// </summary>
		public const string CurrentMeasurePropertyName = "CurrentMeasureDisplayNum";

		/// <summary>
		/// Display measure + 1 to the user 
		/// </summary>
		[Bindable(true)]
		public int CurrentMeasureDisplayNum
		{
			get
			{
				if (CurrentComposition != null)
					return CurrentComposition.CurrentProgression.CurrentMeasure + 1;
				else
					return 0;
			}
			set
			{
				//Do nothing - setter only here to enable UI binding
			}
		}

		/// <summary>
		/// LowNote noteID that can be played during this session
		/// </summary>
		public static int LowNote { get; set; }

		/// <summary>
		/// HighNote noteID that can be played during this session
		/// </summary>
		public static int HighNote { get; set; }

		/// <summary>
		/// Practical resoulation for this session. PPQN divided by this number will determine ticknumber and therefore
		/// the minimum note length that can be processed. 1 means notes will be processed every 96 ticks (or every quarter note),
		/// 2 means every 48 (or eigth note), 4 means every 16th and 8 means every 32nd.
		/// </summary>
		public static int SessionResolution = Convert.ToInt16(AppResources.SessionResolutionString);

		/// <summary>
		/// Number of major ticks in a measure
		/// </summary>
		public int MajorTicksInMeasure
		{
			get
			{
				return CurrentComposition.CurrentProgression.Numerator * SessionResolution;
			}
		}

		/// <summary>
		/// Determines the interval at which the tick handler will process events 
		/// </summary>
		public int TickNumber
		{
			get
			{
				return PPQN / SessionResolution;
			}
		}

		/// <summary>
		/// Number of total times in the phrase that events will be processed
		/// </summary>
		public int MajorTicksInPhrase
		{
			get
			{
				return MajorTicksInMeasure * CurrentComposition.CurrentProgression.TotalMeasures;
			}
		}

		/// <summary>
		/// Current tempo of this session in beats per minute
		/// </summary>
		[Bindable(true)]
		public int BPM
		{
			get
			{
				return m_bpm;
			}
			set
			{
				m_bpm = value;
				NotifyPropertyChanged("BPM");
			}

		}

		/// <summary>
		/// The starting MIDI octave for this composition
		/// </summary>
		static public int? HomeOctave = 0;

		/// <summary>
		/// How many octaves the notes can go up or down
		/// </summary>
		static public int OctaveVariance;

		/// <summary>
		/// Use low octave for bass phrase
		/// </summary>
		static public int LowOctave
		{
			get
			{
				return HomeOctave.Value - OctaveVariance;
			}
		}

		/// <summary>
		/// Convenience property for SessionKey
		/// </summary>
		public const string CurrentKeyPropertyName = "CurrentKey";

		/// <summary>
		/// Current key of this session
		/// </summary>
		[Bindable(true)]
		public string CurrentKey
		{
			get
			{
				return CurrentComposition.CurrentProgression.Key.ToString();
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Key sig selected by the user
		/// </summary>
		[Bindable(true)]
		public int SelectedKeyValue
		{
			get
			{
				return m_selectedKeyValue;
			}
			set
			{
				if (value > 0)
				{
					m_KeySignatureBuilder.Key = (CircleOfFifths.Key)Enum.ToObject(typeof(CircleOfFifths.Key), value);
					m_KeySignatureBuilder.Build();

					CircleOfFifths.SetKey(m_KeySignatureBuilder.Key.ToString());
				}
				else
					SetKey();

				if (value > 0 && value != m_selectedKeyValue)
					LoadComposition(HighNote, LowNote);

				m_selectedKeyValue = (int)CircleOfFifths.CurrentKey;

				NotifyPropertyChanged("SelectedKeyValue");
				//NotifyPropertyChanged("Compositions");
			}
		}

		[Bindable(true)]
		public Dictionary<int, string> Keys
		{
			get
			{
				Dictionary<int, string> keys = new Dictionary<int, string>();
				List<string> keystrings = new List<string>();

				if (m_keyBindingList == null)
				{
					m_keyBindingList = new Dictionary<int, string>();

					m_keyBindingList.Add(-1, "Random Selection");

					foreach (CircleOfFifths.Key key in (CircleOfFifths.Key[])Enum.GetValues(typeof(CircleOfFifths.Key)))
						m_keyBindingList.Add((int)key, key.ToString());
				}

				if (SelectedComposition.CompositionID == 0)
					keys = m_keyBindingList;
				else
				{
					if (m_selectedComposition.Mode == "Ionian")
						keys = m_keyBindingList.Where(k => k.Value.Substring(k.Value.Length - 5, 5) == "Major"
						    || k.Key == -1).ToDictionary(d => d.Key, d => d.Value);
					else
						keys = m_keyBindingList.Where(k => k.Value.Substring(k.Value.Length - 5, 5) == "Minor"
						    || k.Key == -1).ToDictionary(d => d.Key, d => d.Value);
				}

				return keys;
			}
			set
			{
			}
		}

		/// <summary>
		/// Number of beats that comprise a measure in the current session
		/// </summary>
		public static int BeatsInMeasure;

		public static bool TransportOverride = true;

		/// <summary>
		/// Convenience property for TimeSignature
		/// </summary>
		public const string TimeSignaturePropertyName = "TimeSignature";

		/// <summary>
		/// String representation of the number of beats in the measure over the beat note value
		/// </summary>
		[Bindable(true)]
		public string TimeSignature
		{
			get
			{
				if (CurrentComposition != null)
					return String.Format("{0}/{1}", CurrentComposition.CurrentProgression.Numerator, Composition.Denominator);
				else
					return string.Empty;
			}
			set
			{
				//Do nothing for now
			}
		}

		/// <summary>
		/// Convenience property for ScaleDegrees
		/// </summary>
		public const string ScaleDegreesPropertyName = "ScaleDegrees";

		/// <summary>
		/// Scale degrees of the current progression
		/// </summary>
		[Bindable(true)]
		public string ScaleDegrees
		{
			get
			{
				if (CurrentComposition == null)
					return string.Empty;
				else
					return CurrentComposition.CurrentProgression.ScaleDegrees;
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for PhraseLength
		/// </summary>
		public const string PhraseLengthPropertyName = "PhraseLength";

		/// <summary>
		/// Total length in measures of the current progression
		/// </summary>
		[Bindable(true)]
		public int PhraseLength
		{
			get
			{
				if (CurrentComposition == null)
					return 0;
				else
					return CurrentComposition.CurrentProgression.TotalMeasures;
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for MovementName
		/// </summary>
		public const string MovementNamePropertyName = "MovementName";

		/// <summary>
		/// Name of the current movement (not sure why this was necessary)
		/// </summary>
		[Bindable(true)]
		public string MovementName
		{
			get
			{
				if (CurrentComposition != null)
					return CurrentComposition.Name;
				else
					return string.Empty;
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for RhythmName
		/// </summary>
		public const string RhythmNamePropertyName = "RhythmName";

		/// <summary>
		/// Name of the current rhythm type
		/// </summary>
		[Bindable(true)]
		public string RhythmName
		{
			get
			{
				return CurrentComposition.CurrentProgression.DrumPhrase.PhraseRhythm.RhythmName;
			}
		}

		/// <summary>
		/// Convenience property for Tempo
		/// </summary>
		public const string TempoPropertyName = "Tempo";

		/// <summary>
		///  Actual miliseconds per beat of the clock
		/// </summary>
		[Bindable(true)]
		public int Tempo
		{
			get
			{
				//if (m_tempo != m_processor.Tempo)
				//{
				//    m_tempo = (int)m_processor.Tempo;

				//    //Tempo is set in microseconds per beat so we need to calculate that
				//double tmpTempo = (Convert.ToDouble(60) / Tempo) * 1000000.0;

				//    //Set the tempo of the internal clock
				//    Clock.Tempo = (int)tmpTempo;
				//}

				int tempo = (int)m_processor.Tempo;

				//Tempo is set in microseconds per beat so we need to calculate that
				double tmpTempo = (Convert.ToDouble(60) / tempo) * 1000000.0;

				//Set the tempo of the internal clock

				if (tmpTempo > 1.0 && !Double.IsInfinity(tmpTempo))
					Clock.Tempo = (int)tmpTempo;

				return tempo;
			}
			set
			{
				int tempo = (int)m_processor.Tempo;

				if (tempo > value)
				{
					int count = tempo - value;

					for (int i = 0; i < count; i++)
					{
						m_events.Add(new VstMidiEvent(0, 0, 0, ConcreteNote.TempoDownEvent.Data, 0, 0));
						m_processor.Process(m_events);
						m_events.Clear();

						Thread.Sleep(100);
					}
				}
				else if (tempo < value)
				{
					int count = value - tempo;

					for (int i = 0; i < count; i++)
					{
						m_events.Add(new VstMidiEvent(0, 0, 0, ConcreteNote.TempoUpEvent.Data, 0, 0));
						m_processor.Process(m_events);
						m_events.Clear();

						Thread.Sleep(100);
					}
				}


				//m_tempo = value;
			}
		}

		[Bindable(true)]
		public List<int> TempoList
		{
			get
			{
				return m_tempoList;
			}
			set
			{
			}
		}

		/// <summary>
		/// Indicates whether or not metronome is turned on
		/// </summary>
		[Bindable(true)]
		public bool Metronome
		{
			get
			{
				return m_metronome;
			}
			set
			{
				m_metronome = value;
				NotifyPropertyChanged("Metronome");
			}
		}

		/// <summary>
		/// Indicates whether or not crash is enabled
		/// </summary>
		[Bindable(true)]
		public bool Crash
		{
			get
			{
				return m_crash;
			}
			set
			{
				m_crash = value;
				NotifyPropertyChanged("Crash");
			}
		}

		public static bool Paused
		{
			get
			{
				return m_paused;
			}
		}

		public static DateTime StopTime
		{
			get
			{
				return m_stopTime;
			}
			set
			{
				m_stopTime = value;
			}
		}

		/// <summary>
		/// Handler for UI binding
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

		/// <summary>
		/// Handler for static properties
		/// </summary>
		public static event PropertyChangedEventHandler StaticPropertyChanged;

		//MIDI/VST Properties

		/// <summary>
		/// List of all notes of the current progression
		/// </summary>
		[Bindable(true)]
		public List<ConcreteNote> Notes
		{
			get
			{
				return m_notes;
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for DrumNotes
		/// </summary>
		public const string DrumNotesPropertyName = "DrumNotes";

		/// <summary>
		/// List of drum notes in the currently playing progression
		/// </summary>
		[Bindable(true)]
		public List<ConcreteNote> DrumNotes
		{
			get
			{
				return Notes.Where(n => n.Type == ConcreteNote.NoteType.Drum).ToList();
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for BassNotes
		/// </summary>
		public const string BassNotesPropertyName = "BassNotes";

		/// <summary>
		/// List of bass notes in the currently playing progression
		/// </summary>
		[Bindable(true)]
		public List<ConcreteNote> BassNotes
		{
			get
			{
				return Notes.Where(n => n.Type == ConcreteNote.NoteType.Bass).ToList();
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for LeadNotes
		/// </summary>
		public const string LeadNotesPropertyName = "LeadNotes";

		/// <summary>
		/// Notes that comprise the current lead melody
		/// </summary>
		[Bindable(true)]
		public List<ConcreteNote> LeadNotes
		{
			get
			{
				return Notes.Where(n => n.Type == ConcreteNote.NoteType.Lead).ToList();
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for RhythmNotes
		/// </summary>
		public const string RhythmNotesPropertyName = "RhythmNotes";

		/// <summary>
		/// Notes that comprise current rhythm accompanyment
		/// </summary>
		[Bindable(true)]
		public List<ConcreteNote> RhythmNotes
		{
			get
			{
				return Notes.Where(n => n.Type == ConcreteNote.NoteType.Rhythm).ToList();
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for ArpNotes
		/// </summary>
		public const string ArpNotesPropertyName = "ArpNotes";

		/// <summary>
		/// Notes being sent to the arpeggiator
		/// </summary>
		[Bindable(true)]
		public List<ConcreteNote> ArpNotes
		{
			get
			{
				return Notes.Where(n => n.Type == ConcreteNote.NoteType.Arpeggio).ToList();
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for UtilityNotes
		/// </summary>
		public const string UtilityNotesPropertyName = "UtilityNotes";

		/// <summary>
		/// Utility notes (crashes/toms, samples, noises)
		/// </summary>
		[Bindable(true)]
		public List<ConcreteNote> UtilityNotes
		{
			get
			{
				return Notes.Where(n => n.Type == ConcreteNote.NoteType.Utility).ToList();
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Convenience property for CurrentChord
		/// </summary>
		public const string CurrentChordPropertyName = "CurrentChord";

		/// <summary>
		/// The chord that is currently being played
		/// </summary>
		[Bindable(true)]
		public string CurrentChord
		{
			get
			{
				//Chords only change on quarter notes for now
				if (CurrentComposition == null)
					return string.Empty;
				else
				{
					string chord = CurrentComposition.CurrentProgression.Chords.Where(c => c.Key <= (m_currentBeat
					    + (CurrentComposition.Numerator * CurrentMeasure))).OrderByDescending(c => c.Key).First().Value.DisplayName;

					if (chord != m_oldChord)
						m_oldChord = chord;

					return m_oldChord;
				}
			}
			set
			{
				//Do nothing
			}
		}

		/// <summary>
		/// Composition currently being played
		/// </summary>
		public Composition CurrentComposition
		{
			get
			{
				return m_currentComposition;
			}
			private set
			{
				m_currentComposition = value;
			}
		}

		/// <summary>
		/// Convenience property for CurrentDisplayNote
		/// </summary>
		public const string CurrentDisplayNotePropertyName = "CurrentDisplayNote";

		public CompositionLite SelectedComposition
		{
			get
			{
				return m_selectedComposition;
			}
			set
			{
				m_selectedComposition = value;

				if (!m_isPlaying && m_selectedComposition.CompositionID > 0)
				{
					LoadComposition(HighNote, LowNote);
				}

				NotifyPropertyChanged(MovementNamePropertyName);
				NotifyPropertyChanged(CurrentKeyPropertyName);

				NotifyPropertyChanged(PhraseLengthPropertyName);
				NotifyPropertyChanged(TimeSignaturePropertyName);
				NotifyPropertyChanged(ScaleDegreesPropertyName);

				NotifyPropertyChanged("IsKeySelectable");
				NotifyPropertyChanged("SelectedComposition");
				NotifyPropertyChanged("Keys");
			}
		}

		/// <summary>
		/// Note currently selected by user
		/// </summary>
		[Bindable(true)]
		public ConcreteNote CurrentDisplayNote
		{
			get
			{
				return m_currentDisplayNote;
			}
			set
			{
				try
				{
					m_currentDisplayNote = value;
					NotifyPropertyChanged(CurrentDisplayNotePropertyName);
				}
				catch (Exception)
				{
				}
			}
		}

		/// <summary>
		/// Convenience property for DrumsMuted
		/// </summary>
		public const string DrumsMutedPropertyName = "DrumsMuted";

		/// <summary>
		/// Drum mute property
		/// </summary>
		[Bindable(true)]
		public bool DrumsMuted
		{
			get
			{
				return m_drumsMuted;
			}
			set
			{
				m_drumsMuted = value;
				NotifyPropertyChanged(DrumsMutedPropertyName);
			}
		}

		/// <summary>
		/// Convenience property for DrumsMuted
		/// </summary>
		public const string BassMutedPropertyName = "BassMuted";

		/// <summary>
		/// Drum mute property
		/// </summary>
		[Bindable(true)]
		public bool BassMuted
		{
			get
			{
				return m_bassMuted;
			}
			set
			{
				m_bassMuted = value;
				NotifyPropertyChanged(BassMutedPropertyName);
			}
		}

		/// <summary>
		/// Convenience property for DrumsMuted
		/// </summary>
		public const string RhythmMutedPropertyName = "RhythmMuted";

		/// <summary>
		/// Drum mute property
		/// </summary>
		[Bindable(true)]
		public bool RhythmMuted
		{
			get
			{
				return m_rhythmMuted;
			}
			set
			{
				m_rhythmMuted = value;
				NotifyPropertyChanged(RhythmMutedPropertyName);
			}
		}

		/// <summary>
		/// Convenience property for DrumsMuted
		/// </summary>
		public const string MelodyMutedPropertyName = "MelodyMuted";

		/// <summary>
		/// Drum mute property
		/// </summary>
		[Bindable(true)]
		public bool MelodyMuted
		{
			get
			{
				return m_melodyMuted;
			}
			set
			{
				m_melodyMuted = value;
				NotifyPropertyChanged(MelodyMutedPropertyName);
			}
		}

		/// <summary>
		/// Convenience property for DrumsMuted
		/// </summary>
		public const string ArpMutedPropertyName = "ArpMuted";

		/// <summary>
		/// Drum mute property
		/// </summary>
		[Bindable(true)]
		public bool ArpMuted
		{
			get
			{
				return m_arpMuted;
			}
			set
			{
				m_arpMuted = value;
				NotifyPropertyChanged(ArpMutedPropertyName);
			}
		}
		/// <summary>
		/// Convenience property for DrumsMuted
		/// </summary>
		public const string UtilityMutedPropertyName = "UtilityMuted";

		/// <summary>
		/// Drum mute property
		/// </summary>
		[Bindable(true)]
		public bool UtilityMuted
		{
			get
			{
				return m_utilityMuted;
			}
			set
			{
				m_utilityMuted = value;
				NotifyPropertyChanged(UtilityMutedPropertyName);
			}
		}

		/// <summary>
		/// Convenience property for CurrentNote
		/// </summary>
		public const string CurrentNoteIsPlayingPropertyName = "CurrentNoteIsPlaying";

		/// <summary>
		/// Used to notify the UI to turn the "is playing" indicator on/off for the currently playing note.
		/// </summary>
		public bool CurrentNoteIsPlaying
		{
			get
			{
				return m_currentNoteIsPlaying;
			}
			set
			{
				if (CurrentDisplayNote != null)
				{
					System.Diagnostics.Debug.WriteLine(string.Format("Location: {0} | Measure {1}",
					    ((double)m_majorTicksPhrase % (double)MajorTicksInMeasure) / CurrentDisplayNote.MajorTickMultiplier,
					    CurrentMeasure));
				}

				m_currentNoteIsPlaying = value;
				NotifyPropertyChanged(CurrentNoteIsPlayingPropertyName);
			}
		}

		/// <summary>
		/// Boolean indiacator of if phrase is locked via UI
		/// </summary>
		public bool HoldPhrase;

		/// <summary>
		/// Number of times this session has run
		/// </summary>
		public int Iteration
		{
			get
			{
				return m_iteration;
			}
			set
			{
				m_iteration = value;
			}
		}

		[Bindable(true)]
		public bool IsKeySelectable
		{
			get
			{
				return m_selectedComposition.CompositionID > 0;
			}
			set
			{
			}
		}

		#endregion

		#region Methods

		/// <summary>
		/// Looks through notes collection of the drum phrase and decides which MIDI events to add for this tick value
		/// Also adds events for metronaome and crash if they are enabled
		/// </summary>
		private void GetEvents()
		{
			m_noteOnList.Clear();
			m_noteOffList.Clear();

			#region Click Track / Crash
			//if (m_metronome)
			//{
			//    //Send metronome on message at the start of every measure and on every quarter note
			//    if (m_majorTicks == 0)
			//        m_events.Add(Note.MetronomeMeasureOnEvent);
			//    else if (m_majorTicks == SessionResolution || m_majorTicks % SessionResolution == SessionResolution)
			//        m_events.Add(Note.MetronomeQuarterOnEvent);

			//    //Send metronome off message to host every 8th note
			//    if (m_majorTicks == SessionResolution / 2 || m_majorTicks % SessionResolution == SessionResolution / 2)
			//        m_events.Add(Note.MetronomeOffEvent);
			//}

			////Add crash to the end of the occasional measure (and turn it off) if the Crash boolean is set to true
			//if (m_crash)
			//{
			//    if (m_majorTicks == 0 && CurrentMeasure == 0 && RndGenerator.Next(2) == 1)
			//        m_events.Add(Note.CrashOnEvent);
			//    else if (m_majorTicks == SessionResolution / 2 && CurrentMeasure == 0)
			//        m_events.Add(Note.CrashOffEvent);
			//}
			#endregion

			var localnotes = CurrentComposition.CurrentProgression.Notes.ToList();

			//Add all on notes appropriate for the current measure/tick count
			m_noteOnList.AddRange(localnotes.Where(n => n.Location == 0 && n.Measure == 0 && n.Location == m_majorTicksPhrase));
			m_noteOnList.AddRange(localnotes.Where(n => CurrentMeasure == 0 && m_majorTicks > 0 && ((double)n.Location == (double)m_majorTicksPhrase / n.MajorTickMultiplier && n.Measure == CurrentMeasure)));
			m_noteOnList.AddRange(localnotes.Where(n => CurrentMeasure > 0 && ((double)n.Location == ((double)m_majorTicksPhrase % (double)MajorTicksInMeasure) / n.MajorTickMultiplier && n.Measure == CurrentMeasure)));

			//If the currently displaying note got added, indicate that is being played on the UI
			if (CurrentDisplayNote != null)
			{
				if (m_noteOnList.Where(n => CurrentDisplayNote.MessageOnID == n.MessageOnID && CurrentDisplayNote.NoteID == n.NoteID && n.Type != ConcreteNote.NoteType.Drum).Any())
					CurrentNoteIsPlaying = true;
			}

			//Add all off notes appropriate for the current measure/tick count that we haven't added on notes for this cycle
			m_noteOffList.AddRange(localnotes.Where(n => CurrentMeasure == 0 && n.OffLocation == 0 && n.OffMeasure == 0 && n.OffLocation == m_majorTicks && n.Type != ConcreteNote.NoteType.Drum));
			m_noteOffList.AddRange(localnotes.Where(n => m_majorTicks > 0 && ((double)n.OffLocation == (double)m_majorTicksPhrase / n.MajorTickMultiplier && n.OffMeasure == CurrentMeasure && n.Type != ConcreteNote.NoteType.Drum)));
			m_noteOffList.AddRange(localnotes.Where(n => CurrentMeasure > 0 && ((double)n.OffLocation == ((double)m_majorTicksPhrase % (double)MajorTicksInMeasure) / n.MajorTickMultiplier && n.OffMeasure == CurrentMeasure && n.Type != ConcreteNote.NoteType.Drum)));

			//If the currently displaying note is being turned off, reflect it on the UI
			if (CurrentDisplayNote != null)
			{
				if (m_noteOffList.Where(n => CurrentDisplayNote.MessageOffID == n.MessageOffID && CurrentDisplayNote.NoteID == n.NoteID).Any())
					CurrentNoteIsPlaying = false;
			}
			
			//Temporary, for debugging
			var bass_on = m_noteOnList.Where(n => !m_noteOffList.Contains(n) && n.Type == Note.NoteType.Bass).Count();
			var rhythm_on = m_noteOnList.Where(n => !m_noteOffList.Contains(n) && n.Type == Note.NoteType.Rhythm).Count();
			var lead_on = m_noteOnList.Where(n => !m_noteOffList.Contains(n) && n.Type == Note.NoteType.Lead).Count();

			//Add of note events to processing list
			m_events.AddRange(m_noteOffList.Select(n => n.NoteOffEvent).AsEnumerable());

			//Add note on events to event list for processing where the note isn't being turned off
			m_events.AddRange(m_noteOnList.Where(n => !m_noteOffList.Contains(n)).Select(n => n.NoteOnEvent).AsEnumerable());
		}

		private void ProcessTicks()
		{
			//If we are on a beat change...
			if (m_majorTicks == SessionResolution - 1 || m_majorTicks % SessionResolution == SessionResolution - 1)
			{
				//If this is the end of a measure...
				if (m_majorTicks == MajorTicksInMeasure - 1)
				{
					//If this is the last measure, set to 0. If not, iterate.
					if (CurrentComposition.CurrentProgression.CurrentMeasure == CurrentComposition.CurrentProgression.TotalMeasures - 1)
					{
						//For now, kill the melody between progressions
						m_events.AddRange(new VstEventCollection { ConcreteNote.MelodyOffEvent, ConcreteNote.BassOffEvent, ConcreteNote.RhythmOffEvent });

						m_oldProgressionID = CurrentComposition.CurrentProgression.ProgressionID;

						//If this is the last progression in the composition, go to the next one
						if (m_progressionCtr == CurrentComposition.Progressions.Count - 1 && !HoldPhrase)
						{
							//Deselect key and composition
							SelectedKeyValue = 0;
							SelectedComposition = m_compositions[0];

							string tracetext = String.Format("Completed movement: {0} | Elapsed Time: {1} seconds | Memory in use: {2} | Available memory: {3}",
							    CurrentComposition.Name,
							    (DateTime.Now - m_startTime),
							    System.Diagnostics.Process.GetCurrentProcess().WorkingSet64,
							    m_computerInfo.AvailablePhysicalMemory);

							Logger.Log(TraceEventType.Information, tracetext);
							Logger.Log(TraceEventType.Information, string.Format("Errors: {0} | EventErrors: {1} | Clock Ticks: {2}" + System.Environment.NewLine, AudioProcessor.Errors, AudioProcessor.EventErrors, Clock.Ticks));

							AudioProcessor.Errors = 0;
							AudioProcessor.EventErrors = 0;

							m_stopTime = DateTime.Now;
							Logger.Log(TraceEventType.Information, string.Format("Stop Time: {0}", m_stopTime.ToString()));

							m_paused = true;
							Clock.Stop();
							m_events.Add(new VstMidiEvent(0, 0, 0, ConcreteNote.ScrollDownEvent.Data, 0, 0));
							m_processor.Process(m_events);
							SelectedComposition = m_compositions[0];
							LoadComposition(HighNote, LowNote);
							m_events.Clear();
							Tempo = RndGenerator.Next(Int32.Parse(Resources.AppResources.MinTempo), Int32.Parse(Resources.AppResources.MaxTempo)) * 10;
							Thread.Sleep(3000);
							Clock.Continue();
							m_paused = false;

							m_stopTime = DateTime.MinValue;
							Logger.Log(TraceEventType.Information, string.Format("Start Time: {0}", DateTime.Now.ToString()));

							//Start at the first progression. Restart the tick counter as well.
							m_progressionCtr = 0;
							CurrentComposition.CurrentProgression = CurrentComposition.Progressions[m_progressionCtr];

							NotifyPropertyChanged(MovementNamePropertyName);
							NotifyPropertyChanged(CurrentKeyPropertyName);
						}
						//If not, go to the next progression
						else if (!HoldPhrase)
							CurrentComposition.CurrentProgression = CurrentComposition.Progressions[++m_progressionCtr];

						//Either way this last measure of the progression so we have to restart the measure and phrase tick counters
						m_majorTicksPhrase = 0;
						CurrentComposition.CurrentProgression.CurrentMeasure = 0;

						//Notify the UI of progression related changes if the ID has actually been updated
						if (CurrentComposition.CurrentProgression.ProgressionID != m_oldProgressionID)
						{
							NotifyPropertyChanged(PhraseLengthPropertyName);
							NotifyPropertyChanged(TimeSignaturePropertyName);
							NotifyPropertyChanged(ScaleDegreesPropertyName);
							NotifyPropertyChanged(CurrentKeyPropertyName);

							ChangeNoteLists();
						}
					}
					//This isn't the last measure so increment the measure and phrase tick counters
					else
					{
						CurrentComposition.CurrentProgression.CurrentMeasure++;
						m_majorTicksPhrase++;
					}

					//Either way, this is the end of a measure so restart beat counter
					m_majorTicks = 0;
					m_currentBeat = 0;
				}
				//This isn't the end of a measure so iterate beat, tick, and phrase tick counters
				else
				{
					m_currentBeat++;
					m_majorTicks++;
					m_majorTicksPhrase++;
				}

				NotifyPropertyChanged(Session.CurrentChordPropertyName);
			}
			//If its not a beat change, it can't be the end of a phrase or measure so just iterate the ticks
			else
			{
				m_majorTicks++;
				m_majorTicksPhrase++;
			}
		}

		/// <summary>
		/// Sets tempo based on the host
		/// </summary>
		public void SetTempo()
		{
			//Tempo is set in microseconds per beat so we need to calculate that
			double tmpTempo = (Convert.ToDouble(60) / Tempo) * 1000000.0;

			//Set the tempo of the internal clock
			Clock.Tempo = (int)tmpTempo;
		}

		/// <summary>
		/// Thise will select 1 of 30 possible key signatures for the session
		/// </summary>
		/// <returns></returns>
		public CircleOfFifths.Key SetKey(string mod = null)
		{
			//Set key sig for MIDI file
			m_KeySignatureBuilder = new KeySignatureBuilder();

			//No modulation was given so this is the first progression in the composition
			if (mod == null)
			{
				switch (CircleOfFifths.CurrentModeName)
				{
					case CircleOfFifths.ModeName.Ionian:
						m_keyNumber = RndGenerator.Next(12, 23);
						break;
					case CircleOfFifths.ModeName.Aeolian:
						m_keyNumber = RndGenerator.Next(0, 11);
						break;
					case CircleOfFifths.ModeName.HarmonicMinor:
						m_keyNumber = RndGenerator.Next(24, 35);
						break;
				}
			}
			//Modulation from the previous key
			else
			{
				string[] mods = mod.Split(',');

				//We only work with basic modulation. The composer will need to supply a series of modulations for anything special.
				foreach (string s in mods)
				{
					switch (s)
					{
						case "Subdominant":
							if (m_keyNumber == 0 || m_keyNumber == 12 || m_keyNumber == 24)
								m_keyNumber += 11;
							else
								m_keyNumber--;
							break;
						case "Dominant":
							if (m_keyNumber == 11 || m_keyNumber == 23 || m_keyNumber == 25)
								m_keyNumber -= 11;
							else
								m_keyNumber++;
							break;
						case "RelativeMajor":
							m_keyNumber += 12;
							break;
						case "RelativeMinor":
							m_keyNumber -= 12;
							break;
					}
				}
			}

			m_KeySignatureBuilder.Key = (CircleOfFifths.Key)Enum.ToObject(typeof(CircleOfFifths.Key), m_keyNumber);
			m_KeySignatureBuilder.Build();

			CircleOfFifths.SetKey(m_KeySignatureBuilder.Key.ToString());

			return m_KeySignatureBuilder.Key;
		}

		/// <summary>
		/// Load compositions
		/// </summary>
		public void LoadComposition(int highNote, int lowNote, bool oldComposition = false)
		{
			XmlNode nl;
			XmlNodeList progressionList;

			if (m_alreadyPlayed.Count == m_compositionIDs.Count())
				m_alreadyPlayed.Clear();

			byte[] playedints = m_alreadyPlayed.Where(c => c != null).Select(c => c.CompositionID).ToArray();
			byte[] eligible = m_compositionIDs.Where(c => !playedints.Contains(c)).ToArray();

			int compositionid = 0;

			if (SelectedComposition.CompositionID == 0)
			{
				if (!oldComposition)
				{
					int id = eligible.Count();
					compositionid = eligible[RndGenerator.Next((byte)id)];
				}
				else
					compositionid = playedints[playedints.GetUpperBound(0)];

				//May have to move this outside of LoadComposition
				m_selectedComposition = m_compositions[compositionid];
				NotifyPropertyChanged("SelectedComposition");
			}
			else
				compositionid = SelectedComposition.CompositionID;

			nl = m_compositionList.Item(compositionid - 1);

			Composition composition = new Composition();

			HighNote = highNote;
			LowNote = lowNote;

			composition.CompositionID = Convert.ToByte(nl.Attributes.GetNamedItem("CompositionID").InnerText);
			composition.Name = nl.Attributes.GetNamedItem("Name").InnerText;
			composition.Mode = nl.Attributes.GetNamedItem("Mode").InnerText;

            Logger.Log(TraceEventType.Information, string.Format("Loading composition {0}", composition.Name));

			bool modeswitch = CircleOfFifths.CurrentModeName.ToString() != composition.Mode;

			switch (composition.Mode)
			{
				case "Ionian":
					CircleOfFifths.CurrentModeName = CircleOfFifths.ModeName.Ionian;
					break;
				case "Aeolian":
					CircleOfFifths.CurrentModeName = CircleOfFifths.ModeName.Aeolian;
					break;
				case "Harmonic Minor":
					CircleOfFifths.CurrentModeName = CircleOfFifths.ModeName.HarmonicMinor;
					break;
			}

			//ONLY DO THIS IF NO KEY WAS SELECTED
			if (m_selectedKeyValue == 0 || modeswitch)
			{
				NotifyPropertyChanged("Keys");
				composition.KeySignature = SetKey();
				m_selectedKeyValue = (int)m_KeySignatureBuilder.Key;
			}
			else
				composition.KeySignature = m_KeySignatureBuilder.Key;

			CircleOfFifths.ModeName originalmodename = CircleOfFifths.CurrentModeName;

			NotifyPropertyChanged("SelectedKeyValue");

            Logger.Log(TraceEventType.Information, string.Format("New key: {0}", composition.KeySignature.ToString()));

            if (nl.Attributes.GetNamedItem("Numerator") != null)
				composition.Numerator = Convert.ToByte(nl.Attributes.GetNamedItem("Numerator").InnerText);
			else
				composition.Numerator = 4;

			progressionList = nl.SelectNodes("Progression");

            Logger.Log(TraceEventType.Information, "Entering progression loop...");

            foreach (XmlNode pl in progressionList)
			{
				byte b;
				string mod = null;

				if (pl.Attributes.GetNamedItem("Modulation") != null)
					mod = pl.Attributes.GetNamedItem("Modulation").InnerText;

				if (pl != null)
				{
					if (Byte.TryParse(pl.InnerText, out b))
					{
						//If modulation is populated, we need to change keys
						if (!string.IsNullOrEmpty(mod))
							composition.KeySignature = SetKey(mod);

						composition.LoadProgression(pl);
					}
					else
						throw new Exception("No ProgressionID found!");
				}
			}

            Logger.Log(TraceEventType.Information, "Progressions Loaded");

            //Need to move back to the original mode of the composition here
            CircleOfFifths.CurrentModeName = originalmodename;

			CurrentComposition = composition;
			CurrentComposition.CurrentProgression = CurrentComposition.Progressions[0];
			CurrentComposition.CurrentProgression.CurrentMeasure = 0;

			ChangeNoteLists();

			CurrentDisplayNote = (ConcreteNote)m_notefactory.GetNote();

			if (SelectedComposition.CompositionID > 0 && !m_alreadyPlayed.Select(c => c.CompositionID).Contains(composition.CompositionID))
				m_alreadyPlayed.Add(composition);

            Logger.Log(TraceEventType.Information, string.Format("Composition {0} loaded", composition.Name));

            m_iteration++;
		}

		public void PrepareUIProperties()
		{
			//TODO: Move everything below (and associated logic) into the composition loop
			Crash = true;
			//m_notes = new List<ConcreteNote>();

			m_noteOnList = new List<ConcreteNote>();
			m_noteOffList = new List<ConcreteNote>();

			NotifyPropertyChanged("SelectedKeyValue");
			NotifyPropertyChanged("SelectedComposition");
			NotifyPropertyChanged(SuitePropertyName);
			NotifyPropertyChanged(MovementNamePropertyName);
			NotifyUI();
		}

		/// <summary>
		/// Property changed handler coordinates with the dispatcher to make updates on the UI
		/// </summary>
		/// <param name="propertyName"></param>
		private void NotifyPropertyChanged(string propertyName)
		{
			try
			{
				if (PropertyChanged != null)
				{
					SmartDispatcher.BeginInvoke(delegate
					{
						PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
					});
				}
			}
			catch (InvalidOperationException ioe)
			{
				Debug.WriteLine("Exception: " + ioe.Message);
			}
		}

		private static void StaticNotifyPropertyChanged(string propertyName)
		{
			try
			{
				if (StaticPropertyChanged != null)
				{
					SmartDispatcher.BeginInvoke(delegate
					{
						StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
					});
				}
			}
			catch (InvalidOperationException ioe)
			{
				Debug.WriteLine("Exception: " + ioe.Message);
			}
		}

		private void NotifyUI()
		{
			NotifyPropertyChanged(CurrentBeatPropertyName);
			NotifyPropertyChanged(CurrentMeasurePropertyName);
			NotifyPropertyChanged(TempoPropertyName);
		}

		private void ChangeNoteLists()
		{
			m_notes = null;
			m_notes = new List<ConcreteNote>();
			m_notes = CurrentComposition.CurrentProgression.Notes;

			CurrentDisplayNote = null;
			CurrentNoteIsPlaying = false;

			NotifyPropertyChanged(DrumNotesPropertyName);
			NotifyPropertyChanged(BassNotesPropertyName);
			NotifyPropertyChanged(RhythmNotesPropertyName);
			NotifyPropertyChanged(LeadNotesPropertyName);
			NotifyPropertyChanged(ArpNotesPropertyName);
			NotifyPropertyChanged(UtilityNotesPropertyName);

			NotifyPropertyChanged(CurrentDisplayNotePropertyName);
			NotifyPropertyChanged(CurrentNoteIsPlayingPropertyName);

			NotifyPropertyChanged(RhythmNamePropertyName);
		}

		#endregion

		#region UI (Live) Methods

		/// <summary>
		/// Start the MIDI clock
		/// </summary>
		public void Start()
		{
			Tempo = RndGenerator.Next(Int32.Parse(Resources.AppResources.MinTempo), Int32.Parse(Resources.AppResources.MaxTempo)) * 10;

			m_isPlaying = true;
			m_paused = false;
			m_startTime = DateTime.Now;

			string tracetext = String.Format("Aleator clock starting. Start time: {0}", m_startTime.ToString());
			Logger.Log(TraceEventType.Information, tracetext);

			//Start the clock
			Clock.Tick += new EventHandler(Clock_Tick);
			Clock.Start();
		}

		/// <summary>
		/// Stop the MIDI clock
		/// </summary>
		public void Stop()
		{
			m_isPlaying = false;

			//TODO: Stop the worker thread.
			if (m_workerThread != null && m_workerThread.IsAlive)
			{
				try
				{
					m_workerThread.Abort();
					m_workerThread = null;
				}
				catch (ThreadAbortException tae)
				{
					Debug.WriteLine(tae.Message);
				}
			}

			m_paused = true;

			m_stopTime = DateTime.Now;
			m_startTime = DateTime.MinValue;

			string tracetext = String.Format("Aleator clock stopping. Current time: {0}", DateTime.Now.ToString());
			Logger.Log(TraceEventType.Information, tracetext);

			//Reset and stop the clock
			Clock.Tick -= Clock_Tick;
			Clock.Stop();
			Clock.SetTicks(0);

			m_events.Clear();

			m_events.AddRange(new VstEventCollection { ConcreteNote.MelodyOffEvent, ConcreteNote.BassOffEvent, ConcreteNote.RhythmOffEvent });

			m_processor.Process(m_events);
			m_events.Clear();

			//Notes.Clear();
			//CurrentComposition = null;

			CurrentComposition.CurrentProgression = CurrentComposition.Progressions[0];
			CurrentComposition.CurrentProgression.CurrentMeasure = 0;

			m_currentBeat = 0;
			m_majorTicks = 0;
			m_majorTicksPhrase = 0;

			CircleOfFifths.Chords = null;
		}

		/// <summary>
		/// Skip forward or back a composition
		/// </summary>
		/// <param name="move">Move forward or back a composition</param>
		public void ChangeComposition(int move)
		{
			m_events.Clear();

			if (move == 1)
				LoadComposition(HighNote, LowNote);
			else
				LoadComposition(HighNote, LowNote, true);

			CurrentComposition.CurrentProgression = CurrentComposition.Progressions[0];
			CurrentComposition.CurrentProgression.CurrentMeasure = 0;

			NotifyPropertyChanged(MovementNamePropertyName);
			NotifyPropertyChanged(CurrentKeyPropertyName);

			NotifyPropertyChanged(PhraseLengthPropertyName);
			NotifyPropertyChanged(TimeSignaturePropertyName);
			NotifyPropertyChanged(ScaleDegreesPropertyName);

			ChangeNoteLists();
		}

		/// <summary>
		/// Skio forward or back a progression
		/// </summary>
		/// <param name="move">Number to move forward or back</param>
		public void ChangeProgression(int move)
		{
			m_events.Clear();

			CurrentComposition.CurrentProgression = CurrentComposition.Progressions[m_progressionCtr + move];
			CurrentComposition.CurrentProgression.CurrentMeasure = 0;

			NotifyPropertyChanged(MovementNamePropertyName);
			NotifyPropertyChanged(CurrentKeyPropertyName);

			NotifyPropertyChanged(PhraseLengthPropertyName);
			NotifyPropertyChanged(TimeSignaturePropertyName);
			NotifyPropertyChanged(ScaleDegreesPropertyName);

			ChangeNoteLists();
		}

		/// <summary>
		/// Create a new phrase on the fly for this progression. This needs to be rewritten.
		/// </summary>
		/// <param name="phrasetype">Type of phrase to be retriggered</param>
		public void ReTrigger(PhraseFactory.PhraseType phrasetype)
		{
			m_pendingPhraseType = phrasetype;

			switch (phrasetype)
			{
				case PhraseFactory.PhraseType.Drum:
					CurrentComposition.CurrentProgression.Notes.RemoveAll(n => n.Type == Note.NoteType.Drum);
					CurrentComposition.CurrentProgression.DrumPhrase = (DrumPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Drum, CurrentComposition.CurrentProgression);
					break;
				case PhraseFactory.PhraseType.Bass:
					CurrentComposition.CurrentProgression.Notes.RemoveAll(n => n.Type == Note.NoteType.Bass);
					CurrentComposition.CurrentProgression.BassPhrase = (BassPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Bass, CurrentComposition.CurrentProgression);
					break;
				case PhraseFactory.PhraseType.Rhythm:
					CurrentComposition.CurrentProgression.Notes.RemoveAll(n => n.Type == Note.NoteType.Rhythm);
					CurrentComposition.CurrentProgression.RhythmPhrase = (RhythmPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Rhythm, CurrentComposition.CurrentProgression);
					break;
				case PhraseFactory.PhraseType.Melody:
					CurrentComposition.CurrentProgression.Notes.RemoveAll(n => n.Type == Note.NoteType.Lead);
					//TODO: Figure out why its holding onto old melodies
					CurrentComposition.CurrentProgression.Melodies.Clear();
					CurrentComposition.CurrentProgression.LoadMelodies();
					CurrentComposition.CurrentProgression.MelodyPhrase = (MelodyPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Melody, CurrentComposition.CurrentProgression);
					break;
				default:
					break;
			}

			SwapAll();
		}

		/// <summary>
		/// Mute the given phrasetype
		/// </summary>
		/// <param name="phrasetype">Kind of phrase to mute</param>
		public void Mute(PhraseFactory.PhraseType phrasetype)
		{
			switch (phrasetype)
			{
				case PhraseFactory.PhraseType.Drum:
					CurrentComposition.CurrentProgression.DrumPhrase.Mute();
					break;
				case PhraseFactory.PhraseType.Bass:
					CurrentComposition.CurrentProgression.BassPhrase.Mute();
					break;
				case PhraseFactory.PhraseType.Rhythm:
					CurrentComposition.CurrentProgression.RhythmPhrase.Mute();
					break;
				case PhraseFactory.PhraseType.Melody:
					CurrentComposition.CurrentProgression.MelodyPhrase.Mute();
					break;
				default:
					break;
			}
		}

		/// <summary>
		/// Mute the given phrasetype
		/// </summary>
		/// <param name="phrasetype">Kind of phrase to mute</param>
		public void UnMute(PhraseFactory.PhraseType phrasetype)
		{
			switch (phrasetype)
			{
				case PhraseFactory.PhraseType.Drum:
					CurrentComposition.CurrentProgression.DrumPhrase.UnMute();
					break;
				case PhraseFactory.PhraseType.Bass:
					CurrentComposition.CurrentProgression.BassPhrase.UnMute();
					break;
				case PhraseFactory.PhraseType.Rhythm:
					CurrentComposition.CurrentProgression.RhythmPhrase.UnMute();
					break;
				case PhraseFactory.PhraseType.Melody:
					CurrentComposition.CurrentProgression.MelodyPhrase.UnMute();
					break;
				default:
					break;
			}
		}

		private void SwapAll()
		{
			//All of the other phrases of this type that appear in instances of this progression throughout the song (other than the current one) need to be swapped out
			List<ConcreteProgression> progressions = CurrentComposition.Progressions.Where(pr => pr.ProgressionID == CurrentComposition.CurrentProgression.ProgressionID
			    && pr.SequenceID != CurrentComposition.CurrentProgression.SequenceID).ToList();

			//TODO: Fix - currently just recopies the first swapped phrase on top of itself througout the song
			foreach (ConcreteProgression p in progressions)
			{
				switch (m_pendingPhraseType)
				{
					case PhraseFactory.PhraseType.Drum:
						p.Notes.RemoveAll(n => n.Type == Note.NoteType.Drum);
						p.DrumPhrase = (DrumPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Drum, p, CurrentComposition.CurrentProgression.DrumPhrase);
						break;
					case PhraseFactory.PhraseType.Bass:
						p.Notes.RemoveAll(n => n.Type == Note.NoteType.Bass);
						p.BassPhrase = (BassPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Bass, p, CurrentComposition.CurrentProgression.BassPhrase);
						break;
					case PhraseFactory.PhraseType.Rhythm:
						p.Notes.RemoveAll(n => n.Type == Note.NoteType.Rhythm);
						p.RhythmPhrase = (RhythmPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Rhythm, p, CurrentComposition.CurrentProgression.RhythmPhrase);
						break;
					case PhraseFactory.PhraseType.Melody:
						p.Notes.RemoveAll(n => n.Type == Note.NoteType.Lead);
						p.MelodyPhrase = (MelodyPhrase)m_phraseFactory.GetPhrase(PhraseFactory.PhraseType.Melody, p, CurrentComposition.CurrentProgression.MelodyPhrase);
						break;
				}
			}
		}

		/// <summary>
		/// Push all the panic buttons
		/// </summary>
		public static void Kill()
		{
			m_processor.Process(new VstEventCollection { ConcreteNote.MelodyOffEvent, ConcreteNote.BassOffEvent, ConcreteNote.RhythmOffEvent });
		}
		#endregion
	}
}
